// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/android/overscroll_refresh.h"

#include "base/logging.h"

namespace ui {
namespace {

    // Experimentally determined constant used to allow activation even if touch
    // release results in a small upward fling (quite common during a slow scroll).
    const float kMinFlingVelocityForActivation = -500.f;

} // namespace

OverscrollRefresh::OverscrollRefresh(OverscrollRefreshHandler* handler)
    : scrolled_to_top_(true)
    , overflow_y_hidden_(false)
    , scroll_consumption_state_(DISABLED)
    , handler_(handler)
{
    DCHECK(handler);
}

OverscrollRefresh::~OverscrollRefresh()
{
}

void OverscrollRefresh::Reset()
{
    scroll_consumption_state_ = DISABLED;
    handler_->PullReset();
}

void OverscrollRefresh::OnScrollBegin()
{
    ReleaseWithoutActivation();
    if (scrolled_to_top_ && !overflow_y_hidden_)
        scroll_consumption_state_ = AWAITING_SCROLL_UPDATE_ACK;
}

void OverscrollRefresh::OnScrollEnd(const gfx::Vector2dF& scroll_velocity)
{
    bool allow_activation = scroll_velocity.y() > kMinFlingVelocityForActivation;
    Release(allow_activation);
}

void OverscrollRefresh::OnScrollUpdateAck(bool was_consumed)
{
    if (scroll_consumption_state_ != AWAITING_SCROLL_UPDATE_ACK)
        return;

    if (was_consumed) {
        scroll_consumption_state_ = DISABLED;
        return;
    }

    scroll_consumption_state_ = handler_->PullStart() ? ENABLED : DISABLED;
}

bool OverscrollRefresh::WillHandleScrollUpdate(
    const gfx::Vector2dF& scroll_delta)
{
    switch (scroll_consumption_state_) {
    case DISABLED:
        return false;

    case AWAITING_SCROLL_UPDATE_ACK:
        // If the initial scroll motion is downward, never allow activation.
        if (scroll_delta.y() <= 0)
            scroll_consumption_state_ = DISABLED;
        return false;

    case ENABLED:
        handler_->PullUpdate(scroll_delta.y());
        return true;
    }

    NOTREACHED() << "Invalid overscroll state: " << scroll_consumption_state_;
    return false;
}

void OverscrollRefresh::ReleaseWithoutActivation()
{
    bool allow_activation = false;
    Release(allow_activation);
}

bool OverscrollRefresh::IsActive() const
{
    return scroll_consumption_state_ == ENABLED;
}

bool OverscrollRefresh::IsAwaitingScrollUpdateAck() const
{
    return scroll_consumption_state_ == AWAITING_SCROLL_UPDATE_ACK;
}

void OverscrollRefresh::OnFrameUpdated(
    const gfx::Vector2dF& content_scroll_offset,
    bool root_overflow_y_hidden)
{
    scrolled_to_top_ = content_scroll_offset.y() == 0;
    overflow_y_hidden_ = root_overflow_y_hidden;
}

void OverscrollRefresh::Release(bool allow_refresh)
{
    if (scroll_consumption_state_ == ENABLED)
        handler_->PullRelease(allow_refresh);
    scroll_consumption_state_ = DISABLED;
}

} // namespace ui
